package com.fish.common.util;

import com.fish.common.constant.JwtConstant;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT工具类
 */
public class JwtUtil {
    
    /**
     * 获取密钥
     */
    private static SecretKey getSecretKey() {
        return Keys.hmacShaKeyFor(JwtConstant.SECRET_KEY.getBytes(StandardCharsets.UTF_8));
    }
    
    /**
     * 生成Access Token
     *
     * @param userId 用户ID
     * @param username 用户名
     * @return Access Token字符串
     */
    public static String generateAccessToken(Long userId, String username) {
        return generateToken(userId, username, JwtConstant.TOKEN_TYPE_ACCESS, JwtConstant.ACCESS_TOKEN_EXPIRATION);
    }
    
    /**
     * 生成Refresh Token
     *
     * @param userId 用户ID
     * @param username 用户名
     * @return Refresh Token字符串
     */
    public static String generateRefreshToken(Long userId, String username) {
        return generateToken(userId, username, JwtConstant.TOKEN_TYPE_REFRESH, JwtConstant.REFRESH_TOKEN_EXPIRATION);
    }
    
    /**
     * 生成Token（私有方法）
     *
     * @param userId 用户ID
     * @param username 用户名
     * @param tokenType Token类型
     * @param expiration 过期时间（毫秒）
     * @return Token字符串
     */
    private static String generateToken(Long userId, String username, String tokenType, Long expiration) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtConstant.CLAIM_USER_ID, userId);
        claims.put(JwtConstant.CLAIM_USERNAME, username);
        claims.put(JwtConstant.CLAIM_TOKEN_TYPE, tokenType);
        
        Date now = new Date();
        Date expirationDate = new Date(now.getTime() + expiration);
        
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(now)
                .setExpiration(expirationDate)
                .signWith(getSecretKey(), SignatureAlgorithm.HS256)
                .compact();
    }
    
    /**
     * 生成Token（兼容旧方法）
     *
     * @param userId 用户ID
     * @param username 用户名
     * @return Token字符串
     */
    @Deprecated
    public static String generateToken(Long userId, String username) {
        return generateAccessToken(userId, username);
    }
    
    /**
     * 解析Token
     *
     * @param token Token字符串
     * @return Claims
     */
    public static Claims parseToken(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(getSecretKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
    
    /**
     * 从Token中获取用户ID
     *
     * @param token Token字符串
     * @return 用户ID
     */
    public static Long getUserId(String token) {
        Claims claims = parseToken(token);
        return claims.get(JwtConstant.CLAIM_USER_ID, Long.class);
    }
    
    /**
     * 从Token中获取用户名
     *
     * @param token Token字符串
     * @return 用户名
     */
    public static String getUsername(String token) {
        Claims claims = parseToken(token);
        return claims.get(JwtConstant.CLAIM_USERNAME, String.class);
    }
    
    /**
     * 验证Token是否过期
     *
     * @param token Token字符串
     * @return true-已过期 false-未过期
     */
    public static boolean isTokenExpired(String token) {
        try {
            Claims claims = parseToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return true;
        }
    }
    
    /**
     * 验证Token是否有效
     *
     * @param token Token字符串
     * @return true-有效 false-无效
     */
    public static boolean validateToken(String token) {
        try {
            parseToken(token);
            return !isTokenExpired(token);
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 获取Token类型
     *
     * @param token Token字符串
     * @return Token类型
     */
    public static String getTokenType(String token) {
        try {
            Claims claims = parseToken(token);
            return claims.get(JwtConstant.CLAIM_TOKEN_TYPE, String.class);
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 验证是否为Access Token
     *
     * @param token Token字符串
     * @return true-是 false-否
     */
    public static boolean isAccessToken(String token) {
        return JwtConstant.TOKEN_TYPE_ACCESS.equals(getTokenType(token));
    }
    
    /**
     * 验证是否为Refresh Token
     *
     * @param token Token字符串
     * @return true-是 false-否
     */
    public static boolean isRefreshToken(String token) {
        return JwtConstant.TOKEN_TYPE_REFRESH.equals(getTokenType(token));
    }
}